package fr.cephb.joperon.core;

import java.io.File;
import java.io.FileNotFoundException;


import java.util.logging.Logger;

import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.Environment;
import com.sleepycat.db.EnvironmentConfig;

import fr.cephb.berkeley.DBUtils;

/**
 * A Wrapper around a com.sleepycat.db.Environment for Operon
 * @author lindenb
 *
 */
public class Operon
{
/** namespace for operon */
public static final String NS="http://regulon.cng.fr/";
/** default path */
public static final String DB_HOME_DEFAULT="/operon/bdb";
/** default path at ceph */
public static final String DB_HOME_CEPH=DB_HOME_DEFAULT;
/** path for debugging purpose */
public static final String DB_HOME_CEPH2="/operon2/bdb";//for debugging purpose

/** logger */
private Logger _log=Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
/** environment */
private Environment environement=null;
/** mode */
private Mode mode=Mode.READ_ONLY;


private Operon()
	{
	
	}


@Override
/** will call close */
protected void finalize() throws Throwable
	{
	close();
	super.finalize();
	}

/** get the Logger for this object */ 
public Logger log() { return this._log;}

/** get the delegate Environment */
public Environment getEnvironment()
	{
	return this.environement;
	}

/** get the open mode */
public Mode getMode()
	{
	return this.mode;
	}

/** close the environement */
public void close() throws DatabaseException
	{
	if(this.environement!=null)
		{
		DBUtils.safeClose(this.environement);
		this.environement=null;
		}
	}

/** close the environement without throwing an exception */
public void safeClose()
	{
	try {
		close();
	} catch (Exception e) {
		e.printStackTrace();
		}
	this.environement=null;
	}


/**
 * creates a new instance of operon using env variables
 * first test DB_HOME
 * then test OPERON_HOME
 * default /operon/bdb
 * @return
 * @throws DatabaseException
 */
public static Operon newInstance() throws DatabaseException
	{
	return newInstance(Mode.READ_ONLY);
	}

/** tries to find the correct path for the environement of BerkeleyDB
 * first looks in <code>$DB_HOME</code>
 * then looks in <code>${OPERON_HOME}/bdb</code>
 *  finally uses DB_HOME_DEFAULT
 *  */
public static String guessBerkeleyDBHome()
	{
	String home= System.getenv("DB_HOME");
	if(home==null)
		{
		System.err.println("$DB_HOME undefined");
		home= System.getenv("OPERON_HOME");
		if(home==null) System.err.println("$OPERON_HOME undefined");
		if(home!=null) home+="/bdb";
		}
	if(home==null)
		{
		home= DB_HOME_DEFAULT;
		}
	return home;
	}


/**
 * creates a new instance of operon for with a given mode calling <code>guessBerkeleyDBHome</code>
 * to guess the position of the environment

 */
public static Operon newInstance(Mode mode) throws DatabaseException
	{
	String home= guessBerkeleyDBHome();
	//System.err.println("Operon: Using "+home);
	return newInstance(new File(home),mode);
	}

/** create a new instance of operon READ_ONLY in the given dbHome */
public static Operon newInstance(File dbHome) throws DatabaseException
	{
	return newInstance(dbHome,Mode.READ_ONLY);
	}



private static EnvironmentConfig createEnvironmentConfig(Mode mode)
	{
	EnvironmentConfig cfg= new EnvironmentConfig();
	
	switch (mode)
			{
		case READ_ONLY:
			cfg.setAllowCreate(false);
			break;
		case WRITE:
			cfg.setAllowCreate(false);//false
			break;
		case CREATOR:
			cfg.setAllowCreate(false);//false
			break;
		default: throw new IllegalArgumentException(mode.toString());
		}
	
	return cfg;
	}

/** create a new instance of operon in the given dbHome and open-mode */
public static Operon newInstance(File dbHome,Mode mode) throws DatabaseException
	{
	Operon op= new Operon();
	op.mode= mode;
	EnvironmentConfig envConfig= createEnvironmentConfig(Mode.READ_ONLY);
	

	try
		{
		op.environement= new Environment(dbHome,envConfig);	
		}
	catch (DatabaseException err)
		{
		throw err;
		}
	catch (FileNotFoundException err)
		{
		err.printStackTrace();
		throw new DatabaseException("Cannot open "+dbHome+" "+err.getMessage());
		} 
	
	if(op.environement==null && 1==2)
		{
		//http://kr.forums.oracle.com/forums/thread.jspa?threadID=464131
		envConfig.setTransactional(true);
		envConfig.setAllowCreate(true);
		envConfig.setRunRecovery(true);
		envConfig.setInitializeCache(true);
		envConfig.setCacheSize(25 * 1024 * 1024); // 25MB cache
		envConfig.setInitializeLocking(true);
		envConfig.setInitializeLogging(true);
	
	
		try {
			op.environement= new Environment(dbHome,envConfig);
			}
		catch (FileNotFoundException err)
			{
			throw new DatabaseException(err.getMessage());
			} 
		catch (DatabaseException err)
			{
			throw err;
			}
		}
	return op;
	
	}

@Override
	public String toString() {
		return "[Operon]";
		}
/** test, ignore */
public static void main(String[] args) {
	Operon op= null;
	try {
		op= Operon.newInstance();
		System.err.println("ok");
		}
	catch (Exception e)
		{
		e.printStackTrace();
		}
	finally
		{
		if(op!=null) op.safeClose();
		}
}
}
